//
// FlapPacket.cs
//
// Copyright (c) 2007 Lukas Lipka.
//

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using IcqSharp.Util;

namespace IcqSharp.Packets
{
    public class FlapPacket
    {
        public const byte Id = 0x2A;
      
        private uint channel;
        private ushort sequence;
        
        private MemoryStream data;
        private EndianBinaryWriter data_writer;

        public FlapPacket (uint channel, ushort sequence, byte[] data)
        {
            this.channel = channel;
            this.sequence = sequence;
            
            this.data = (data == null) ? new MemoryStream () : new MemoryStream (data);
            this.data_writer = new EndianBinaryWriter (EndianBitConverter.Big, this.data);
        }

        public FlapPacket (uint channel, byte[] data)
            : this (channel, 0, data)
        {
        }

        public FlapPacket (uint channel)
            : this (channel, null)
        {
        }

        public void Add (byte[] value)
        {
            data_writer.Write (value);
        }

        public void AddDword (UInt32 value)
        {
            data_writer.Write (value);
        }

        public virtual void AddTlv(Tlv tlv)
        {
            data_writer.Write(tlv.GetBytes());
        }

        public void SetSequence(ushort sequence)
        {
            this.sequence = sequence;
        }

        public virtual byte[] Write ()
        {
            byte[] buffer = new byte [4 + (data != null ? 2 + data.Length : 0)];

            buffer[0] = Id;
            buffer[1] = (byte)channel;

            byte[] bytes = EndianBitConverter.Big.GetBytes (sequence);
            Array.Copy (bytes, 0, buffer, 2, 2);

            if (data != null)
            {
                bytes = EndianBitConverter.Big.GetBytes ((ushort)data.Length);
                Array.Copy (bytes, 0, buffer, 4, 2);
                Array.Copy (data.ToArray (), 0, buffer, 6, (int)data.Length);
            }

            return buffer;
        }

        public static FlapPacket Parse (byte[] data)
        {
            if (data [0] != Id)
                throw new FormatException ("FLAP packet malformed!");

            uint channel = data [1];
            ushort sequence = EndianBitConverter.Big.ToUInt16 (data, 2);
            ushort data_size = EndianBitConverter.Big.ToUInt16 (data, 4);
            
            byte[] buffer = new byte[data_size];
            Array.Copy (data, 6, buffer, 0, data_size);

            FlapPacket packet = new FlapPacket (channel, sequence, buffer);

            return packet;
        }

        public uint Channel
        {
            get { return channel; }
        }

        public ushort Sequence
        {
            get { return sequence; }
        }

        public virtual byte[] Data
        {
            get { return data.ToArray (); }
            set { data = new MemoryStream (value); }
        }
    }
}
